/**
 *
 * User: Zhikang.Peng
 * Date: 2018/07/26 15:56
 */
package heap

import "gitee.com/thghh/jvmgo/classfile"

type ExceptionTable []*ExceptionHandler

type ExceptionHandler struct {
	startPc   int
	endPc     int
	handlerPc int
	catchType *ClassRef
}

// 把class文件中的异常处理表转换成 ExceptionTable类型
func newExceptionTable(entrys []*classfile.ExceptionTableEntry, cp *ConstantPool) ExceptionTable {
	table := make([]*ExceptionHandler, len(entrys))
	for i, entry := range entrys {
		table[i] = &ExceptionHandler{
			startPc:   int(entry.StartPc()),
			endPc:     int(entry.EndPc()),
			handlerPc: int(entry.HandlerPc()),
			catchType: getCatchType(uint(entry.CatchType()), cp),
		}
	}
	return table
}

// 从运行时常量池中查找类符号引用
func getCatchType(index uint, cp *ConstantPool) *ClassRef {
	if index == 0 {
		return nil
	}
	return cp.GetConstant(index).(*ClassRef)
}

/**
start_pc和end_pc可以锁定一部分字节码，这部分字节码对应某个可能抛出异
常的try{}代码块。catch_type是个索引，通过它可以从运行时常量池
中查到一个类符号引用，解析后的类是个异常类,假定这个类是
X。如果位于start_pc和end_pc之间的指令抛出异常x，且x是X（或者
X的子类）的实例，handler_pc就指出负责异常处理的catch{}块在哪
里。
*/
func (self ExceptionTable) findExceptionHandler(exClass *Class, pc int) *ExceptionHandler {
	for _, handler := range self {
		if pc >= handler.startPc && pc < handler.endPc {
			if handler.catchType == nil {
				return handler // catch-all
			}
			catchClass := handler.catchType.ResolvedClass() // X
			// exClass extends catchClass
			if catchClass == exClass || catchClass.IsSuperClassOf(exClass) {
				return handler
			}
		}
	}
	return nil
}
